package org.xm.sk.service.data.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xm.sk.dao.CouponRepository;
import org.xm.sk.vo.ob.PageConf;
import org.xm.sk.vo.tb.Activity;
import org.xm.sk.vo.tb.Boder;
import org.xm.sk.vo.tb.Coupon;

@Service
@Transactional
public class CouponServiceImpl extends BaseServiceImpl<Coupon> {

    private static final String CACHE_KEY = "'coupon'";
    private static final String sk_CACHE_NAME = "coupons";

    @Autowired
    private CouponRepository couponRepository;

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public Coupon findById(int id) {
        return this.couponRepository.getOne(id);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public Set<Coupon> findByName(String name) {
        return this.couponRepository.findByName(name);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_all'")
    public List<Coupon> findAll() {
        return this.couponRepository.findAll();
    }

    // @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public List<Coupon> findAll(Coupon coupon) {
        ExampleMatcher matcher = ExampleMatcher.matching();
        Example<Coupon> ex = Example.of(coupon, matcher);
        return this.couponRepository.findAll(ex);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public Object findAllByPage(PageConf pageConf) {
        List<Order> orders = new ArrayList<Order>();
        if (null != pageConf.getSortNames()) {
            for (int i = 0; i < pageConf.getSortNames().size(); i++) {
                orders.add(new Order(pageConf.getSortOrders().get(i),
                        pageConf.getSortNames().get(i)));
            }
        } else {
            orders.add(new Order(Direction.DESC, "id"));
        }
        Sort sort = Sort.by(orders);
        Pageable pageable = null;
        Specification<Coupon> querySpecifi = new Specification<Coupon>() {

            private static final long serialVersionUID = 7354945891080685951L;

            @Override
            public Predicate toPredicate(Root<Coupon> root,
                    CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                Predicate predicate = cb.and(
                        cb.equal(root.get("datalevel").as(Integer.class), 0));
                List<Predicate> predicates = new ArrayList<>();
                if (null != pageConf.getSearch()
                        && 0 < pageConf.getSearch().trim().length()) {
                    String search = pageConf.getSearch().trim();
                    // 模糊查找
                    predicates.add(cb.like(root.get("name").as(String.class),
                            "%" + search + "%"));
                    Join<Coupon, Activity> joinActivity = root.join("activity",
                            JoinType.LEFT);
                    predicates.add(
                            cb.like(joinActivity.get("name").as(String.class),
                                    "%" + search + "%"));
                    predicates
                            .add(cb.like(root.get("couponnum").as(String.class),
                                    "%" + search + "%"));
                    predicates
                            .add(cb.like(root.get("shopName").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(cb.like(
                            root.get("hairdresserName").as(String.class),
                            "%" + search + "%"));
                    predicates
                            .add(cb.like(root.get("userName").as(String.class),
                                    "%" + search + "%"));
                    Join<Coupon, Boder> joinBoder = root.join("boder",
                            JoinType.LEFT);
                    predicates.add(
                            cb.like(joinBoder.get("ordernum").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("creatorName").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("editerName").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("modifydate").as(String.class),
                                    "%" + search + "%"));
                    String status = null;
                    if ("正常".contains(search)) {
                        status = "0";
                    }
                    if ("已用".contains(search)) {
                        status = "1";
                    }
                    if ("生效中".contains(search)) {
                        status = "2";
                    }
                    if ("过期".contains(search)) {
                        status = "3";
                    }
                    if (null != status) {
                        predicates.add(cb.like(
                                root.get("status").as(String.class), status));
                    }
                }
                if (predicates.isEmpty())
                    return predicate;
                // and到一起的话所有条件就是且关系，or就是或关系
                return cb.and(
                        cb.or(predicates
                                .toArray(new Predicate[predicates.size()])),
                        predicate);
            }
        };
        if (null != pageConf.getPage() && null != pageConf.getSize())
            pageable = PageRequest.of(pageConf.getPage(), pageConf.getSize(),
                    sort);
        if (null != pageable)
            return this.couponRepository.findAll(querySpecifi, pageable);
        else
            return this.couponRepository.findAll(querySpecifi, sort);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0+'_'+#p1")
    public Object findAllByPage(PageConf pageConf, Object object) {
        if (null != object && object instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> map = (Map<String, Object>) object;
            if (null != map.get("userid")) {
                Integer userid = Integer.valueOf(map.get("userid").toString());
                if (null != map.get("activityid")) {
                    Integer activityid = Integer.valueOf(map.get("activityid").toString());
                    return this.couponRepository.listByUserIdAndActivityId(userid, activityid);
                } else {
                    Pageable pageable = PageRequest.of(pageConf.getPage(),
                            pageConf.getSize());
                    return this.couponRepository.list4Client(pageable, userid);
                }
            } else if (null != map.get("hairdresserId")) {
                Integer hairdresserId = Integer
                        .valueOf(map.get("hairdresserId").toString());
                Pageable pageable = PageRequest.of(pageConf.getPage(),
                        pageConf.getSize());
                return this.couponRepository.list4Hairdresser(pageable,
                        hairdresserId);
            } else {
                return null;
            }
        } else {
            return findAllByPage(pageConf);
        }
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    // @CachePut(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0.id")
    public Coupon update(Coupon coupon) {
        coupon.setEditer(user().getUserid());
        coupon.setEditerName(user().getUsername());
        coupon.setModifydate(new Date());
        return this.couponRepository.save(coupon);
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    public void delete(int id) {
        this.couponRepository.delete(id, user().getUserid(),
                user().getUsername());
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    public void delete(Set<Integer> ids) {
        this.couponRepository.delete(ids, user().getUserid(),
                user().getUsername());
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    public Coupon add(Coupon coupon) {
        coupon.setCreator(user().getUserid());
        coupon.setEditer(user().getUserid());
        coupon.setCreatorName(user().getUsername());
        coupon.setEditerName(user().getUsername());
        return this.couponRepository.saveAndFlush(coupon);
    }

}
